﻿using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

namespace XYRendering.Vegetation
{
    public class VGInstancingDataRenererManager
    {
        private static VGInstancingDataRenererManager s_Instance;
        public static VGInstancingDataRenererManager GetInstance()
        {
            if (s_Instance == null)
            {
                s_Instance = new VGInstancingDataRenererManager();
                s_Instance.Init();
            }

            return s_Instance;
        }

        public static void DestoryInstance()
        {
            if (s_Instance != null)
            {
                s_Instance.UnInit();
                s_Instance = null;
            }
        }

        public bool isEnable = true;
        public bool isDeviceSupported => SystemInfo.supportsInstancing;

        VGBatchingOption _batchOption = VGBatchingOption.Batching_511;

        public VGBatchingOption batchOption
        {
            get => _batchOption;
            set
            {
                bool hasChange = _batchOption != value;
                _batchOption = value;
                if (hasChange)
                    OnBatchingOptionChange();
            }
        } 
        
        List<VGInstancingDataRenderer> _allRenderers = new List<VGInstancingDataRenderer>();

        
        
        VGBatchUtils _batchUtils;

        IVGInstancingMaterialManager _materialManager;
        
        public void Init()
        {
            if (!isDeviceSupported)
                return;
            
            _batchUtils = new VGBatchUtils(batchOption);
            _materialManager = new VGInstancingMaterialManager();
            _materialManager.OnInit();
        }

        
        public void UnInit()
        {
           _batchUtils.Clear();
           _materialManager.OnDestory();
        }

        public void Register(VGInstancingDataRenderer renderer)
        {
            _allRenderers.Add(renderer);
        }

        public void UnRegister(VGInstancingDataRenderer renderer)
        {
            _allRenderers.Remove(renderer);  
        }

        void OnBatchingOptionChange()
        {
            _batchUtils.Clear();
            _batchUtils = new VGBatchUtils(batchOption);
        }


        public bool PrepareForExecute()
        {
            if (!isEnable)
                return false;
            
            if (!isDeviceSupported)
                return false;
                
            _batchUtils.Clear();
            
            _materialManager.OnPreRendering();
            
            foreach (var renderer in _allRenderers)
            {
                renderer.CommitInstances(_batchUtils, _materialManager);
            }
            
            return _batchUtils.numInstances > 0;
        }


        public void OnPreExecute(CommandBuffer cmd)
        {

        }


        public void Execute(CommandBuffer cmd)
        {
            if (!isDeviceSupported)
                return;
                
            for (int i = 0; i < _batchUtils.numBatches; i++)
            {
                VGInstancingBatch batch = _batchUtils[i];
                
                if (!batch.canExecute)
                    continue;
                
                batch.UpdateOcclusionAndLightProbesData();
                batch.material.enableInstancing = true;
                cmd.DrawMeshInstanced(batch.mesh, 0, batch.material, 0, batch.instancesMatrixs, batch.numInstances, batch.mpb);
            }
            
        }

        public void OnPostExecute(CommandBuffer cmd)
        {
            if (!isDeviceSupported)
                return;
            
            _batchUtils.Clear();
            _materialManager.OnPostRendering();
        }


        #region DebugPreview


#if  UNITY_EDITOR
        
        public int GetRenderCount => _allRenderers.Count;

        
        public int GetTotlyRenderingNum()
        {
            int sum = 0;
            for (int i = 0; i < _batchUtils.numBatches; i++)
            {
                VGInstancingBatch batch = _batchUtils[i];
                if (!batch.canExecute)
                    continue;
                sum+= batch.numInstances;
            }

            return sum;
        }


        public int GetFullRenderingNum()
        {

            return _batchUtils.numInstances;


        }
        
        
        
        

#endif
        #endregion 
        
    }
}